home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / libraries / dylan / range.dylan < prev    next >
Encoding:
Text File  |  1995-03-15  |  33.2 KB  |  1,089 lines  |  [TEXT/ttxt]

  1. module: Dylan
  2. rcs-header: $Header: range.dylan,v 1.6 94/11/03 23:51:04 wlott Exp $
  3.  
  4. //======================================================================
  5. //
  6. // Copyright (c) 1994  Carnegie Mellon University
  7. // All rights reserved.
  8. // 
  9. // Use and copying of this software and preparation of derivative
  10. // works based on this software are permitted, including commercial
  11. // use, provided that the following conditions are observed:
  12. // 
  13. // 1. This copyright notice must be retained in full on any copies
  14. //    and on appropriate parts of any derivative works.
  15. // 2. Documentation (paper or online) accompanying any system that
  16. //    incorporates this software, or any part of it, must acknowledge
  17. //    the contribution of the Gwydion Project at Carnegie Mellon
  18. //    University.
  19. // 
  20. // This software is made available "as is".  Neither the authors nor
  21. // Carnegie Mellon University make any warranty about the software,
  22. // its performance, or its conformity to any specification.
  23. // 
  24. // Bug reports, questions, comments, and suggestions should be sent by
  25. // E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  26. //
  27. //======================================================================
  28. //
  29. // This file contains definitions of classes and functions for the
  30. // Dylan range collection class.  Ranges represent linear arithmetic
  31. // sequences, which may be infinitely long.
  32. //
  33.  
  34.  
  35.  
  36. /* Dylan Range Class Definition
  37.  
  38.    Objects of the class <range> represent linear arithmetic sequences
  39.    (here sequence is the mathematical term as well as the collection
  40.    term).  Ranges are special collections because they may be
  41.    infinitely long.
  42.  
  43.    A range is defined by six keyword arguments to the constructor
  44.    function RANGE -- from:, by:, to:, above:, below:, and size:.  Any
  45.    of these may be given or omitted; the behavior of the range depends
  46.    on the combination of keywords given.  The FROM and BY keywords
  47.    have default values 0 and 1 respectively.  The range created begins
  48.    at FROM and increases by an increment of BY.
  49.  
  50.    The endpoint of the range is determined by the combination of the
  51.    to:, above:, below:, and size: keywords.  TO is an inclusive bound
  52.    independent of the direction of the range.  ABOVE is an exclusive
  53.    lower bound and BELOW is and exclusive upper bound.  The range will
  54.    have no more than SIZE elements.
  55.  
  56.    The range representation used in this code is simplified so that
  57.    only the from, by, and a size value need to be stored.  The
  58.    original representation (using TO, ABOVE, or whatever) is
  59.    translated to this representation by the function
  60.    COMPUTE-RANGE-SIZE.
  61.  
  62. */
  63.  
  64. // <range> -- public
  65. // 
  66. // The <range> abstract class represents ranges (linear arithmetic
  67. // sequences).  The class has slots to store the FROM and BY
  68. // parameters of the range and a virtual slot RANGE-DIRECTION.
  69. // 
  70. // The concrete subclasses that implement the range protocol are
  71. // <bounded-range> and <unbounded-range>.
  72. //
  73. define abstract class <range> (<sequence>)
  74.    slot range-from :: <real>,
  75.       init-value: 0,
  76.       init-keyword: from:;
  77.    slot range-by :: <real>,
  78.       init-value: 1,
  79.       init-keyword: by:;
  80.    virtual slot range-direction,
  81.       setter: #f;
  82. end class;
  83.  
  84.  
  85. // range-direction -- internal
  86. // 
  87. // This implements the virtual slot RANGE-DIRECTION.  Returns the
  88. // direction of the range.  If the range increment BY is positive, the
  89. // range has the direction #"increasing", if negative, #"decreasing",
  90. // and if zero, #"none".
  91. //
  92. define method range-direction (range :: <range>)
  93.       => direction :: <symbol>;
  94.    let r-by = range.range-by;
  95.    case
  96.       r-by = 0 => #"none";
  97.       r-by > 0 => #"increasing";
  98.       r-by < 0 => #"decreasing";
  99.    end case;
  100. end method;
  101.  
  102.  
  103. // <unbounded-range> -- extremely internal
  104. // 
  105. // Class to represent unbounded (infinite) ranges.
  106. // 
  107. // MAKE should never be called on <unbounded-range> except for the few
  108. // places in the range constructor.  Please use RANGE instead.
  109. //
  110. define class <unbounded-range> (<range>) end class;
  111.  
  112.  
  113. // <bounded-range> -- extremely internal
  114. // 
  115. // Class to represent bounded (finite) ranges.  This class adds a size
  116. // slot to the <range> class.
  117. // 
  118. // MAKE should never be called on <bounded-range> except for the few
  119. // places in the range constructor.  Please use RANGE instead.
  120. //
  121. define class <bounded-range> (<range>)
  122.    slot range-size :: <fixed-integer>,
  123.       required-init-keyword: size:;
  124. end class;
  125.  
  126.  
  127.  
  128. /* Range Utility Functions
  129.  
  130.    This section contains functions that are used to do the computation
  131.    needed to set up a range.  Such computations include figuring out
  132.    what the size of a range should be given its FROM, BY, TO, ABOVE,
  133.    BELOW, and SIZE parameters.
  134.  
  135. */
  136.  
  137. // compute-range-size -- internal
  138. // 
  139. // This function translates the (from, by, to, above, below, size)
  140. // representation of the user to the (from, by, size) (bounded) or
  141. // (from, by) (unbounded) internal representation.
  142. // 
  143. // The size returned by COMPUTE-RANGE-SIZE is the smallest range size
  144. // such that:
  145. // 1) the first (if any) element of the range is FROM and its
  146. //    increment is BY
  147. // 2) the range has no element less than ABOVE or greater than BELOW
  148. // 3) the range has no element greater than TO + BY if BY is positive,
  149. //    or no element less than TO + BY if BY is negative
  150. // 4) the size of the range is no greater than SIZE
  151. // 
  152. // Size limitations for each of the arguments are computed.  Valid
  153. // sizes (sizes not #f) are taken.
  154. // 
  155. // If there are no valid sizes, #f is returned.  (Everywhere in this
  156. // implementation of ranges, a size of #f denotes an unbounded range.)
  157. // If valid sizes exists the maximum of 0 and the minimum of the valid
  158. // sizes is returned.
  159. //
  160. define constant <false-or-real> =
  161.    union (singleton (#f), <real>);
  162.  
  163. define constant <false-or-fixed> =
  164.    union (singleton (#f), <fixed-integer>);
  165.  
  166. define method compute-range-size (r-from :: <real>,
  167.                   r-by :: <real>,
  168.                   r-to :: <false-or-real>,
  169.                   r-above :: <false-or-real>,
  170.                   r-below :: <false-or-real>,
  171.                   r-size :: <false-or-fixed>)
  172.       => size :: <false-or-fixed>;
  173.    let to-size = r-to & compute-to-size (r-from, r-by, r-to);
  174.    let above-size = r-above & compute-above-size (r-from, r-by, r-above);
  175.    let below-size = r-below & compute-below-size (r-from, r-by, r-below);
  176.    let size-size = r-size;
  177.  
  178.    let valid-sizes =
  179.       choose (identity, list (to-size, above-size, below-size, size-size));
  180.  
  181.    if (empty? (valid-sizes))
  182.       #f
  183.    else
  184.       max (0, apply (min, valid-sizes))
  185.    end if;
  186. end method;
  187.  
  188.  
  189. // compute-to-size -- internal
  190. // 
  191. // Computes the limiting size of a TO argument to RANGE.  This size is
  192. // one plus the nearest integer larger than
  193. // 
  194. //         (BOUND - START) / INCREMENT
  195. // 
  196. // (See also APPROXIMATE-RANGE-KEY.  The TO size limit is essentially
  197. // the larger approximate key for BOUND (plus 1).)
  198. // 
  199. // (The <integer> method is slightly optimized for case where the
  200. // increment is +1 or -1.)
  201. //
  202. define method compute-to-size (start :: <fixed-integer>,
  203.                    increment :: <fixed-integer>,
  204.                    bound :: <fixed-integer>)
  205.       => to-size :: <false-or-fixed>;
  206.    select (increment by \=)
  207.       0 =>
  208.      #f;
  209.       1 =>
  210.      bound - start + 1;
  211.       -1 =>
  212.      -(bound - start) + 1;
  213.       otherwise =>
  214.      ceiling/ (bound - start, increment) + 1;
  215.    end select;
  216. end method;
  217. //
  218. define method compute-to-size (start :: <real>,
  219.                    increment :: <real>,
  220.                    bound :: <real>)
  221.       => to-size :: <false-or-fixed>;
  222.    select (increment by \=)
  223.       0 =>
  224.      #f;
  225.       otherwise =>
  226.      ceiling/ (bound - start, increment) + 1;
  227.    end select;
  228. end method;
  229.  
  230.  
  231. // compute-above-size -- internal
  232. // 
  233. // Computes the limiting size of an ABOVE argument to RANGE.  This
  234. // size is the nearest integer larger than
  235. // 
  236. //         (BOUND - START) / INCREMENT
  237. // 
  238. // if the increment is negative (the range is decreasing toward the
  239. // ABOVE bound.)
  240. // 
  241. // If the range is not decreasing, then if START if above ABOVE, #f is
  242. // returned (no limiting size).  But if START is below ABOVE, 0 is
  243. // returned.
  244. //
  245. define method compute-above-size (start :: <fixed-integer>,
  246.                   increment :: <fixed-integer>,
  247.                   bound :: <fixed-integer>)
  248.       => above-size :: <false-or-fixed>;
  249.    if (negative? (increment))
  250.       if (increment = -1)
  251.      -(bound - start)
  252.       else
  253.      ceiling/ (bound - start, increment)
  254.       end if;
  255.    else
  256.       if (bound < start)
  257.      #f
  258.       else
  259.      0
  260.       end if;
  261.    end if;
  262. end method;
  263. //
  264. define method compute-above-size (start :: <real>,
  265.                   increment :: <real>,
  266.                   bound :: <real>)
  267.       => above-size :: <false-or-fixed>;
  268.    if (negative? (increment))
  269.       ceiling/ (bound - start, increment)
  270.    else
  271.       if (bound < start)
  272.      #f
  273.       else
  274.      0
  275.       end if;
  276.    end if;
  277. end method;
  278.  
  279.  
  280. // compute-below-size -- internal
  281. //
  282. // Computes the limiting size of an BELOW argument to RANGE.  This size is
  283. // the nearest integer larger than
  284. // 
  285. //         (BOUND - START) / INCREMENT
  286. // 
  287. // if the increment is positive (the range is increasing toward the
  288. // BELOW bound.)
  289. // 
  290. // If the range is not increasing, then if START if below BELOW, #f is
  291. // returned (no limiting size).  But if START is above BELOW, 0 is
  292. // returned.
  293. //
  294. define method compute-below-size (start :: <fixed-integer>,
  295.                   increment :: <fixed-integer>,
  296.                   bound :: <fixed-integer>)
  297.       => below-size :: <false-or-fixed>;
  298.    if (positive? (increment))
  299.       if (increment = 1)
  300.      bound - start
  301.       else
  302.      ceiling/ (bound - start, increment)
  303.       end if;
  304.    else
  305.       if (bound > start)
  306.      #f
  307.       else
  308.      0
  309.       end if;
  310.    end if;
  311. end method;
  312. //
  313. define method compute-below-size (start :: <real>,
  314.                   increment :: <real>,
  315.                   bound :: <real>)
  316.       => below-size :: <false-or-fixed>;
  317.    if (positive? (increment))
  318.       if (increment = 1)
  319.      bound - start
  320.       else
  321.      ceiling/ (bound - start, increment)
  322.       end if;
  323.    else
  324.       if (bound > start)
  325.      #f
  326.       else
  327.      0
  328.       end if;
  329.    end if;
  330. end method;
  331.  
  332.  
  333. // approximate-range-key -- internal
  334. //
  335. // Returns the key of the element of RANGE nearest to ELEMENT.  The
  336. // approximate key for a number N is the integer nearest
  337. // 
  338. //             (N - FROM) / BY
  339. //
  340. define method approximate-range-key (range :: <range>, element :: <real>)
  341.       => key :: <fixed-integer>;
  342.    round/ (element - range.range-from, range.range-by)
  343. end method;
  344.  
  345.  
  346.  
  347. /* Range Functions
  348.  
  349.    This section includes the special range constructor RANGE, and
  350.    other functions special to the implementation of ranges, such as
  351.    ELEMENT, and the method for BINARY=.
  352.  
  353. */
  354.  
  355. // range -- public
  356. // 
  357. // RANGE is the constructor for ranges.  It accepts six keywords --
  358. // from:, by:, to:, above:, below:, and size:.  It uses
  359. // COMPUTE-RANGE-SIZE to find the appropriate size for the new range.
  360. // If this size is #f an unbounded range is created, otherwise a
  361. // bounded range is made.
  362. //
  363. define constant range =
  364.    method (#key from: r-from = 0, by: r-by = 1,
  365.        to: r-to = #f, above: r-above = #f, below: r-below = #f,
  366.        size: r-size = #f)
  367.      => new-range :: <range>;
  368.       let range-size =
  369.      compute-range-size (r-from, r-by, r-to, r-above, r-below, r-size);
  370.       if (range-size)
  371.      make (<bounded-range>, from: r-from, by: r-by, size: range-size);
  372.       else
  373.      make (<unbounded-range>, from: r-from, by: r-by);
  374.       end if;
  375.    end method;
  376.  
  377.  
  378. // make -- public
  379. // 
  380. // The MAKE method for abstract class <range> applies RANGE, the range
  381. // constructor, to the keyword arguments.  This produces an instance
  382. // of one of the concrete subclasses <bounded-range> or
  383. // <unbounded-range>.
  384. //
  385. define method make (class-to-make == <range>, #rest keys, #all-keys)
  386.       => new-range :: <range>;
  387.    apply (range, keys);
  388. end method;
  389.  
  390.  
  391. // element -- public
  392. // 
  393. // Returns the element of the range corresponding to KEY.  This
  394. // element is found using FROM + KEY * BY.  If KEY is out of the
  395. // bounds of the range, the default is returned or an error is
  396. // signalled.
  397. //
  398. define method element (range :: <bounded-range>, key :: <fixed-integer>,
  399.                        #key default = no-default)
  400.       => range-element :: <real>;
  401.    case
  402.       (key >= 0) & (key < range.range-size) =>
  403.          range.range-from + (key * range.range-by);
  404.       (default == no-default) =>
  405.          error ("No such element in %=: %d", range, key);
  406.       otherwise =>
  407.          default;
  408.    end case;
  409. end method;
  410. //
  411. define method element (range :: <unbounded-range>, key :: <fixed-integer>,
  412.                        #key default = no-default)
  413.       => range-element :: <real>;
  414.    case
  415.       (key >= 0) =>
  416.          range.range-from + (key * range.range-by);
  417.       (default == no-default) =>
  418.          error ("No such element in %=: %d", range, key);
  419.       otherwise =>
  420.          default;
  421.    end case;
  422. end method;
  423.  
  424.  
  425. // = -- public
  426. // 
  427. // Ranges are = if their beginning points, increments, and sizes are
  428. // equal.
  429. //
  430. define method \= (range1 :: <range>, range2 :: <range>)
  431.       => equal? :: <boolean>;
  432.    range1.range-from = range2.range-from
  433.       & range1.range-by = range2.range-by
  434.       & range1.range-size = range2.range-size;
  435. end method;
  436.  
  437.  
  438.  
  439. /* Iteration Protocol
  440.  
  441.    Iteration states for ranges are simply the integer keys, since we
  442.    have an efficient way of calculating any element of the range.
  443.  
  444.    For bounded ranges we have to check the state against the size of the
  445.    range.  Iteration over unbounded ranges does not terminate (i.e.
  446.    NEXT-STATE never returns #f).
  447.  
  448. */
  449.  
  450. // forward-iteration-protocol -- public
  451. // 
  452. define method forward-iteration-protocol (range :: <bounded-range>)
  453.       => (initial-state :: <object>, limit :: <object>,
  454.       next-state :: <function>, finished-state? :: <function>,
  455.       current-key :: <function>, current-element :: <function>,
  456.       current-element-setter :: <function>, copy-state? :: <function>);
  457.    let initial-state = 0;
  458.    let limit = range.range-size;
  459.    local method next-state (r :: <range>, s :: <fixed-integer>)
  460.         s + 1
  461.      end method;
  462.    local method finished-state? (r :: <range>, s :: <fixed-integer>,
  463.                  l :: <fixed-integer>)
  464.         s = l
  465.      end method;
  466.    local method current-key (r :: <range>, s :: <fixed-integer>)
  467.         s
  468.      end method;
  469.    local method current-element (r :: <range>, s :: <fixed-integer>)
  470.         r[s];
  471.      end method;
  472.    local method current-element-setter (r :: <range>, s :: <fixed-integer>,
  473.                     value)
  474.             error ("CURRENT-ELEMENT-SETTER not applicable for <range>");
  475.      end method;
  476.    local method copy-state (r :: <range>, s :: <fixed-integer>)
  477.         s
  478.      end method;
  479.    values (initial-state, limit, next-state, finished-state?, current-key,
  480.        current-element, current-element-setter, copy-state);
  481. end method;
  482. //
  483. define method forward-iteration-protocol (range :: <unbounded-range>)
  484.       => (initial-state :: <object>, limit :: <object>,
  485.       next-state :: <function>, finished-state? :: <function>,
  486.       current-key :: <function>, current-element :: <function>,
  487.       current-element-setter :: <function>, copy-state? :: <function>);
  488.    let initial-state = 0;
  489.    let limit = #f;
  490.    local method next-state (r :: <range>, s :: <fixed-integer>)
  491.         s + 1
  492.      end method;
  493.    local method finished-state? (r :: <range>, s :: <fixed-integer>, l)
  494.         #f
  495.      end method;
  496.    local method current-key (r :: <range>, s :: <fixed-integer>)
  497.         s
  498.      end method;
  499.    local method current-element (r :: <range>, s :: <fixed-integer>)
  500.         r[s];
  501.      end method;
  502.    local method current-element-setter (r :: <range>, s :: <fixed-integer>, 
  503.                     value)
  504.             error ("CURRENT-ELEMENT-SETTER not applicable for <range>");
  505.      end method;
  506.    local method copy-state (r :: <range>, s :: <fixed-integer>)
  507.         s
  508.      end method;
  509.    values (initial-state, limit, next-state, finished-state?, current-key,
  510.        current-element, current-element-setter, copy-state);
  511. end method;
  512.  
  513.  
  514.  
  515. /* Collection Function Methods
  516.  
  517.    The collection functions which have methods specialized for ranges
  518.    are SIZE, CLASS-FOR-COPY, EMPTY?, and MEMBER?.  These methods are
  519.    defined in this section.
  520.  
  521.    Ranges use the default methods for the collection functions DO,
  522.    MAP, ANY?, EVERY?, and FIND-KEY.
  523.  
  524.    Ranges have no methods for SIZE-SETTER because they are not
  525.    stretchy.  Ranges do not have methods for MAP-AS, MAP-INTO,
  526.    REPLACE-ELEMENTS!, and FILL! because they are not mutable.
  527.  
  528.    The methods for REDUCE and REDUCE1 for unbounded ranges signal an
  529.    error, since reduction over unbounded ranges will not terminate.
  530.  
  531.    Note that using some of the default methods on unbounded ranges may
  532.    cause infinite loops.  For example, uses of DO, MAP, ANY?, or
  533.    EVERY? on unbounded ranges may never terminate.  (On the other
  534.    hand, they might terminate, so we do not make this an error.)
  535.  
  536. */
  537.  
  538. // size -- public
  539. // 
  540. // SIZE for unbounded ranges returns #f.
  541. //
  542. define method sizes (range :: <bounded-range>)
  543.    range.range-size
  544. end method;
  545. //
  546. define method size (range :: <unbounded-range>)
  547.    #f
  548. end method;
  549.  
  550.  
  551. // class-for-copy -- public
  552. // 
  553. define method class-for-copy (range :: <range>)
  554.    <list>
  555. end method;
  556.  
  557.  
  558. // empty? -- public
  559. // 
  560. // A bounded range is empty if the size is zero.  An unbounded range
  561. // can never be empty.
  562. //
  563. define method empty? (range :: <bounded-range>)
  564.    range.range-size = 0
  565. end method;
  566. //
  567. define method empty? (range :: <unbounded-range>)
  568.    #f
  569. end method;
  570.  
  571.  
  572. // reduce reduce1
  573. // 
  574. // Trying to reduce an unbounded range will not terminate.
  575. //
  576. define method reduce (procedure :: <function>, initial-value,
  577.               range :: <unbounded-range>)
  578.    error ("REDUCE not applicable for unbounded <range>");
  579. end method;
  580. //
  581. define method reduce1 (procedure :: <function>, range :: <unbounded-range>)
  582.    error ("REDUCE1 not applicable for unbounded <range>");
  583. end method;
  584.  
  585.  
  586. // member? -- public
  587. // 
  588. // MEMBER? for ranges must terminate even if the range is unbounded.
  589. // The way to check to see if a number N is an element of a range is
  590. // to compute its approximate key in the range.  Then if the
  591. // approximate key is within the bounds of the range and if the value
  592. // tests with the element at the key, MEMBER? returns #t.
  593. //
  594. define method member? (value :: <real>, range :: <bounded-range>,
  595.                #key test = \==)
  596.    let approximate-position =
  597.       if (range.range-by = 0)
  598.      0
  599.       else
  600.      approximate-range-key (range, value)
  601.       end if;
  602.  
  603.    if (approximate-position >= 0 & approximate-position < range.range-size)
  604.       test (value, range[approximate-position])
  605.    else
  606.       #f
  607.    end if;
  608. end method;
  609. //
  610. define method member? (value :: <real>, range :: <unbounded-range>,
  611.                #key test = \==)
  612.    let approximate-position =
  613.       if (range.range-by = 0)
  614.      0
  615.       else
  616.      approximate-range-key (range, value)
  617.       end if;
  618.  
  619.    if (approximate-position >= 0)
  620.       test (value, range[approximate-position])
  621.    else
  622.       #f
  623.    end if;
  624. end method;
  625.  
  626.  
  627.  
  628. /* Sequence Function Methods
  629.  
  630.    The sequence functions which have methods specialized for ranges
  631.    are INTERSECTION, COPY-SEQUENCE, REVERSE, and LAST.  These methods
  632.    are defined in this section.
  633.  
  634.    Ranges use the default methods for the sequence functions ADD(!),
  635.    ADD-NEW(!), REMOVE(!), CHOOSE, CHOOSE-BY, UNION,
  636.    REMOVE-DUPLICATES(!), CONCATENATE, REPLACE-SUBSEQUENCE!, SORT(!),
  637.    FIRST, SECOND, THIRD, and SUBSEQUENCE-POSITION.
  638.  
  639.    Ranges do not have methods for CONCATENATE-AS, and FIRST- SECOND-
  640.    THIRD- LAST-SETTER because they are not mutable.
  641.  
  642.    The methods for ADD, ADD-NEW, CHOOSE, REMOVE-DUPLICATES, REVERSE,
  643.    SORT, and LAST for unbounded ranges signal an error, since any of
  644.    these over unbounded ranges will not terminate.
  645.  
  646.    Note that using some of the default methods on unbounded ranges may
  647.    cause infinite loops.  For example, uses of CHOOSE-BY, UNION,
  648.    CONCATENATE, and REPLACE-SUBSEQUENCE! on unbounded ranges may never
  649.    terminate.
  650.  
  651. */
  652.  
  653. // add
  654. //
  655. define method add (range :: <unbounded-range>, new)
  656.    error ("ADD not applicable for unbounded <range>");
  657. end method;
  658.  
  659.  
  660. // add-new
  661. //
  662. define method add-new (range :: <unbounded-range>, new, #key test)
  663.    error ("ADD-NEW not applicable for unbounded <range>");
  664. end method;
  665.  
  666.  
  667. // choose
  668. //
  669. define method choose (predicate :: <function>, range :: <unbounded-range>)
  670.    error ("CHOOSE not applicable for unbounded <range>");
  671. end method;
  672.  
  673.  
  674. // intersection -- public
  675. // 
  676. // Range intersection is quite complicated, so the implementation is
  677. // included in its own section below.
  678.  
  679.  
  680. // remove-duplicates
  681. //
  682. define method remove-duplicates (range :: <unbounded-range>, #key test)
  683.    error ("REMOVE-DUPLICATES not applicable for unbounded <range>");
  684. end method;
  685.  
  686.  
  687. // copy-sequence -- public
  688. // 
  689. // Returns a range which is a copy of the source range.  The START and
  690. // END keywords specify at which elements of the range copying should
  691. // begin and end.
  692. // 
  693. // For bounded ranges, correct values for COPY-START and COPY-END are
  694. // found with respect to the range, and RANGE is called with the right
  695. // length and other parameters from the original range.
  696. // 
  697. // For unbounded ranges, a bounded range is returned if END is
  698. // supplied, and an unbounded range if not.
  699. //
  700. define method copy-sequence (source :: <bounded-range>,
  701.                  #key start: copy-start = 0, end: copy-end)
  702.    let r-size = source.range-size;
  703.    let r-from = source.range-from;
  704.    let r-by = source.range-by;
  705.    let copy-start = if (copy-start >= 0)
  706.                copy-start
  707.             else
  708.                0
  709.             end if;
  710.    let copy-end = if (copy-end)
  711.              copy-end
  712.           else
  713.              r-size
  714.           end if;
  715.    if (copy-start > copy-end) 
  716.      error("End: (%=) is smaller than start: (%=)", copy-start, copy-end);
  717.    end if;
  718.  
  719.    case
  720.       copy-start > r-size =>
  721.      range (size: 0);
  722.       copy-end > r-size =>
  723.      range (from: source[copy-start], by: r-by,
  724.         size: r-size - copy-start);
  725.       otherwise =>
  726.      range (from: source[copy-start], by: r-by,
  727.         size: copy-end - copy-start);
  728.    end case;
  729. end method;
  730. //
  731. define method copy-sequence (source :: <unbounded-range>,
  732.                  #key start: copy-start = 0, end: copy-end)
  733.    let r-from = source.range-from;
  734.    let r-by = source.range-by;
  735.    let copy-start = if (copy-start >= 0)
  736.                copy-start
  737.             else
  738.                0
  739.             end if;
  740.    if (copy-end)
  741.       range (from: source[copy-start], by: r-by,
  742.          size: copy-end - copy-start);
  743.    else
  744.       range (from: source[copy-start], by: r-by);
  745.    end if;
  746. end method;
  747.  
  748.  
  749. // reverse -- public
  750. // 
  751. // For bounded ranges REVERSE returns a new range from: the last
  752. // element of the original range, by: the negative of the original by,
  753. // with size: the size of the original range.
  754. // 
  755. // Unbounded ranges cannot be reversed.p
  756. //
  757. define method reverse (range-to-reverse :: <bounded-range>)
  758.    range (from: last (range-to-reverse, default: range-to-reverse.range-from),
  759.       by: negative (range-to-reverse.range-by),
  760.       size: range-to-reverse.range-size);
  761. end method;
  762. //
  763. define method reverse (range :: <unbounded-range>)
  764.    error ("REVERSE not applicable for unbounded <range>");
  765. end method;
  766.  
  767.  
  768. // reverse! -- public
  769. // 
  770. // For bounded ranges, REVERSE! sets RANGE-FROM to the last element of
  771. // the range and RANGE-BY to the negative of the original by, and
  772. // returns the range.
  773. // 
  774. // Unbounded ranges cannot be REVERSED!.
  775. //
  776. define method reverse! (range :: <bounded-range>)
  777.    range.range-from := last (range, default: range.range-from);
  778.    range.range-by := negative (range.range-by);
  779.    range
  780. end method;
  781. //
  782. define method reverse! (range :: <unbounded-range>)
  783.    error ("REVERSE! not applicable for unbounded <range>");
  784. end method;
  785.  
  786.  
  787. // sort
  788. //
  789. define method sort (range :: <unbounded-range>, #key test, stable)
  790.    error ("SORT not applicable for unbounded <range>");
  791. end method;
  792.  
  793.  
  794. // last -- public
  795. // 
  796. // Returns the element at RANGE-SIZE - 1.  Signals an error for
  797. // unbounded ranges.
  798. //
  799. define method last (range :: <bounded-range>, #key default = no-default)
  800.    element (range, range.range-size - 1, default: default)
  801. end method;
  802. //
  803. define method last (range :: <unbounded-range>, #key default)
  804.    error ("LAST not applicable for unbounded <range>");
  805. end method;
  806.  
  807.  
  808.  
  809. /*
  810.               Range Intersection
  811.  
  812.    INTERSECTION for ranges is required to return even for unbounded
  813.    ranges.  So the algorithm used for range intersection must be able
  814.    to find an intersection for unbounded ranges.  Fortunately this is
  815.    not too hard with the representation of ranges used here.
  816.  
  817.    The steps of finding the intersection of two ranges are:
  818.  
  819.    1) Find the interval in which the two ranges must intersect.  This
  820.       interval may be infinitely long in one direction.
  821.  
  822.    2) If the interval is finite, find the finite intersection of the
  823.       two ranges within that interval.
  824.  
  825.       If the interval is infinite, find the unbounded increasing or
  826.       decreasing (one or the other) intersection of the two ranges
  827.       within that interval.
  828.  
  829.    The functions to do these steps are defined below.  Step 1 is
  830.    performed by INTERSECTION-INTERVAL.  Step 2 is performed by one of
  831.    FINITE-INTERSECTION, INCREASING-INTERSECTION, or
  832.    DECREASING-INTERSECTION.
  833.  
  834. */
  835.  
  836. // intersection -- public
  837. // 
  838. // The method on sequence intersection for ranges.  If the TEST is ==
  839. // or =, INTERSECTION will produce a range as its result.  If not,
  840. // then the sequence produced is the result of the default sequence
  841. // method for ranges.
  842. //
  843. define method intersection (range1 :: <range>, range2 :: <range>,
  844.                 #next next-method, #key test = \==)
  845.       => sequence :: <sequence>;
  846.    if (test == \== | test == \=)
  847.       range-intersection (range1, range2, test: test);
  848.    else
  849.       next-method ();
  850.    end if;
  851. end method;
  852.  
  853.  
  854. // range-intersection -- internal
  855. // 
  856. // Return a new range which is the intersection of the two ranges.
  857. // 
  858. // This is done by finding the interval of intersection of the two
  859. // ranges, and calculating the either finite, infinite increasing, or
  860. // infinite decreasing intersection withing the interval.
  861. //
  862. define method range-intersection (range1 :: <range>, range2 :: <range>,
  863.                   #key test)
  864.       => range :: <range>;
  865.    let (x-from, x-to) = intersection-interval (range1, range2);
  866.    case
  867.       ~ x-from =>
  868.      decreasing-intersection (range1, range2, test: test);
  869.       ~ x-to =>
  870.      increasing-intersection (range1, range2, test: test);
  871.       otherwise =>
  872.      finite-intersection (range1, range2, test: test);
  873.    end case;
  874. end method;
  875.  
  876.  
  877. // finite-intersection -- internal
  878. // 
  879. // Returns a bounded range containing the intersection of the two
  880. // ranges.  The keys in RANGE1 of the bounds of the intersection
  881. // interval are computed.  Then all the elements of RANGE1 between
  882. // these keys which are also elements of RANGE2 are found.  A new
  883. // range beginning at the first element (if any) of elements and
  884. // ending at the last with the increment of the second - the first is
  885. // returned.
  886. //
  887. define method finite-intersection (range1 :: <range>, range2 :: <range>,
  888.                    #key test)
  889.       => range :: <bounded-range>;
  890.    let (x-from, x-to) = intersection-interval (range1, range2);
  891.    let from-key = approximate-range-key (range1, x-from);
  892.    let to-key = approximate-range-key (range1, x-to);
  893.    let intersection =
  894.       if (range1.range-direction == #"increasing")
  895.      choose (rcurry (member?, range2, test: test),
  896.          copy-sequence (range1, start: from-key, end: to-key + 1));
  897.       else
  898.      choose (rcurry (member?, range2, test: test),
  899.          copy-sequence (range1, start: to-key, end: from-key + 1));
  900.       end if;
  901.    select (intersection.size by \=)
  902.       0 =>
  903.      range (size: 0);
  904.       1 =>
  905.          range (from: intersection.first, size: 1);
  906.       otherwise =>
  907.          range (from: intersection.first, to: intersection.last,
  908.         by: intersection.second - intersection.first);
  909.    end select;
  910. end method;
  911.  
  912.  
  913. // increasing-intersection -- internal
  914. // 
  915. // Returns an unbounded increasing range containing the intersection
  916. // of the two ranges.  BY is taken to be the least common multiple of
  917. // the BYs of RANGE1 and RANGE2.  The key in RANGE1 of the lower
  918. // intersection interval bound is found, and the upper key is taken to
  919. // be the key of the lower bound + BY (because the intersection
  920. // interval has no upper bound).  (If the intersection has any
  921. // elements, there must be one within BY of the bottom of the
  922. // intersection interval.)
  923. // 
  924. // The elements of RANGE1 between these keys which are also elements
  925. // of RANGE2 are found, and a new range beginning with the first of
  926. // these (if any) and with an increment of BY is returned.
  927. //
  928. define method increasing-intersection (range1 :: <unbounded-range>,
  929.                        range2 :: <unbounded-range>,
  930.                        #key test)
  931.       => range :: <unbounded-range>;
  932.    let (x-from, x-to) = intersection-interval (range1, range2);
  933.    let x-by = lcm (range1.range-by, range2.range-by);
  934.    let from-key = approximate-range-key (range1, x-from);
  935.    let to-key = approximate-range-key (range1, x-from + 2 * x-by);
  936.    let intersection =
  937.       choose (rcurry (member?, range2, test: test),
  938.           copy-sequence (range1, start: from-key, end: to-key));
  939.    if (empty? (intersection))
  940.       range (size: 0);
  941.    else
  942.       range (from: intersection.first, by: x-by);
  943.    end if;
  944. end method;
  945.  
  946.  
  947. // decreasing-intersection -- internal
  948. // 
  949. // Returns an unbounded decreasing range containing the intersection
  950. // of the two ranges.  BY is taken to be the least common multiple of
  951. // the BYs of RANGE1 and RANGE2.  The key in RANGE1 of the upper
  952. // intersection interval bound is found, and the lower key is taken to
  953. // be the key of the upper bound + BY (because the intersection
  954. // interval has no lower bound).  (If the intersection has any
  955. // elements, there must be one within BY of the top of the
  956. // intersection interval.)
  957. // 
  958. // The elements of RANGE1 between these keys which are also elements
  959. // of RANGE2 are found, and a new range beginning with the first of
  960. // these (if any) and with an increment of BY is returned.
  961. //
  962. define method decreasing-intersection (range1 :: <unbounded-range>,
  963.                        range2 :: <unbounded-range>,
  964.                        #key test)
  965.       => range :: <unbounded-range>;
  966.    let (x-from, x-to) = intersection-interval (range1, range2);
  967.    let x-by = -lcm (-range1.range-by, -range2.range-by);
  968.    let from-key = approximate-range-key (range1, x-to + 2 * x-by);
  969.    let to-key = approximate-range-key (range1, x-to);
  970.    let intersection =
  971.       choose (rcurry (member?, range2, test: test),
  972.           copy-sequence (range1, start: to-key, end: from-key));
  973.    if (empty? (intersection))
  974.       range (size: 0);
  975.    else
  976.       range (from: intersection.first, by: x-by);
  977.    end if;
  978. end method;
  979.  
  980.  
  981. // range-directions -- internal
  982. // 
  983. // Returns a symbol denoting the respective directions of RANGE1 and
  984. // RANGE2.
  985. //
  986. define method range-directions (range1 :: <range>, range2 :: <range>)
  987.       => direction :: <symbol>;
  988.    if (range1.range-direction == #"increasing")
  989.       if (range2.range-direction == #"increasing")
  990.      #"increasing-increasing"
  991.       else
  992.      #"increasing-decreasing"
  993.       end if;
  994.    else
  995.       if (range2.range-direction == #"increasing")
  996.      #"decreasing-increasing"
  997.       else
  998.      #"decreasing-decreasing"
  999.       end if;
  1000.    end if;
  1001. end method;
  1002.  
  1003.  
  1004. // intersection-interval -- internal
  1005. // 
  1006. // Returns the lower and upper bounds of the interval in which the two
  1007. // ranges intersect.
  1008. // 
  1009. // For any intersection with a bounded range, the intersection
  1010. // interval will be finite.  The first number returned is always lower
  1011. // than the second.
  1012. // 
  1013. // For two unbounded ranges, the interval of intersection may be
  1014. // infinitely long in one direction or the other.  In this case one of
  1015. // the bounds will be #f (using the convention in this code that #f
  1016. // represents an unbounded size).
  1017. //
  1018. define method intersection-interval (range1 :: <bounded-range>,
  1019.                      range2 :: <bounded-range>)
  1020.       => (x-from :: <false-or-fixed>, x-to :: <false-or-fixed>);
  1021.    let from1 = range1.range-from;
  1022.    let to1 = range1.last;
  1023.    let from2 = range2.range-from;
  1024.    let to2 = range2.last;
  1025.    select (range-directions (range1, range2))
  1026.       #"increasing-increasing" =>
  1027.      values (max (from1, from2), min (to1, to2));
  1028.       #"increasing-decreasing" =>
  1029.      values (max (from1, to2), min (to1, from2));
  1030.       #"decreasing-increasing" =>
  1031.      values (max (to1, from2), min (from1, to2));
  1032.       #"decreasing-decreasing" =>
  1033.      values (max (to1, to2), min (from1, from2));
  1034.    end select;
  1035. end method;
  1036. //
  1037. define method intersection-interval (range1 :: <bounded-range>,
  1038.                      range2 :: <unbounded-range>)
  1039.       => (x-from :: <false-or-fixed>, x-to :: <false-or-fixed>);
  1040.    let from1 = range1.range-from;
  1041.    let to1 = range1.last;
  1042.    let from2 = range2.range-from;
  1043.    select (range-directions (range1, range2))
  1044.       #"increasing-increasing" =>
  1045.      values (max (from1, from2), to1);
  1046.       #"increasing-decreasing" =>
  1047.      values (from1, min (to1, from2));
  1048.       #"decreasing-increasing" =>
  1049.      values (max (to1, from2), from1);
  1050.       #"decreasing-decreasing" =>
  1051.      values (to1, min (from1, from2));
  1052.    end select;
  1053. end method;
  1054. //
  1055. define method intersection-interval (range1 :: <unbounded-range>,
  1056.                      range2 :: <bounded-range>)
  1057.       => (x-from :: <false-or-fixed>, x-to :: <false-or-fixed>);
  1058.    let from1 = range1.range-from;
  1059.    let from2 = range2.range-from;
  1060.    let to2 = range2.last;
  1061.    select (range-directions (range1, range2))
  1062.       #"increasing-increasing" =>
  1063.      values (max (from1, from2), to2);
  1064.       #"increasing-decreasing" =>
  1065.      values (max (from1, to2), from2);
  1066.       #"decreasing-increasing" =>
  1067.      values (from2, min (from1, to2));
  1068.       #"decreasing-decreasing" =>
  1069.      values (to2, min (from1, from2));
  1070.    end select;
  1071. end method;
  1072. //
  1073. define method intersection-interval (range1 :: <unbounded-range>,
  1074.                      range2 :: <unbounded-range>)
  1075.       => (x-from :: <false-or-fixed>, x-to :: <false-or-fixed>);
  1076.    let from1 = range1.range-from;
  1077.    let from2 = range2.range-from;
  1078.    select (range-directions (range1, range2))
  1079.       #"increasing-increasing" =>
  1080.      values (max (from1, from2), #f);
  1081.       #"increasing-decreasing" =>
  1082.      values (from1, from2);
  1083.       #"decreasing-increasing" =>
  1084.      values (from2, from1);
  1085.       #"decreasing-decreasing" =>
  1086.      values (#f, min (from1, from2));
  1087.    end select;
  1088. end method;
  1089.